package collection;

import java.util.*;

public class BasicCollectionDemo {

    // 数组的缺陷:
    // 数组初始化后大小不可变；
    // 数组只能按索引顺序存取。

    // 集合:可以在内部持有若干其他Java对象，并对外提供访问接口;本身也是一个Java对象
    // 集合的大小是可变的。
    // 集合只能存放对象,不能存放基本数据类型,但集合可以有不同种类的元素



    // Java的集合类Collection定义在java.util包中，是除Map外所有其他集合类的根接口
    // 集合实现了接口和实现类相分离，例如，有序表的接口是List，具体的实现类有ArrayList，LinkedList等
    // 集合支持泛型，我们可以限制在一个集合中只能放入同一种数据类型的元素
    // 主要提供了3种集合类，包括List，Set和Map。
    // Java集合使用统一的Iterator遍历，无需关心存储方式
    // 尽量不要使用遗留接口:Enumeration<E>：已被Iterator<E>取代;遗留类:Hashtable,vector,Stack

    public void listExample(){

        // list列表=线性表,实现自List接口,底层是用数组实现的
        // 线性表内部维护的是一个可动态进行扩容的数组，也就是我们之前所说的顺序表
        // 是一个有序的集合，插入元素默认是插入到尾部，按顺序从前往后存放，每个元素都有一个自己的下标位置
        // 列表中允许存在重复元素
        // 集合类是支持嵌套使用的，一个集合中可以存放多个集合
        ArrayList<String> list = new ArrayList<>();
        list.add("树脂666");
        String str ="树脂666";
        list.add("树脂666");
        System.out.println("打印集合类，可以得到一个非常规范的结果"+list);

        list.remove(str);
        System.out.println("这种情况下，只会删除排在前面的第一个元素"+list);

        // 集合类在删除元素时，只会调用equals方法进行判断是否为指定元素，而不是进行等号判断
        // 如果两个对象使用equals方法相等，那么集合中就是相同的两个对象

        // 我们在使用Integer时，要注意传参问题
        List<Integer> list2 = new ArrayList<>();
        list2.add(10);   //添加Integer的值10
        list2.remove((Integer) 10);   //注意，不能直接用10，默认情况下会认为传入的是int类型值，删除的是下标为10的元素
        System.out.println("更改为为10的Integer对象,可以看到，此时元素成功被移除"+list2);   //可以看到，此时元素成功被移除

        list2.add(new Integer(10));   //添加的是一个对象
        list2.remove(new Integer(10));   //删除的是另一个对象
        System.out.println("根据.equals删除成功"+list2);



        List<String> list3 = Arrays.asList("A", "B", "C");   //非常方便
        System.out.println("在Arrays工具类中，我们可以快速生成一个只读的List");
        System.out.println("不能进行修改操作，只能使用获取内容相关的方法，否则抛出 UnsupportedOperationException 异常"+list3);

        // 使用匿名内部类（匿名内部类在Java8无法使用钻石运算符，但是之后的版本可以）
        List<String> list4 = new ArrayList<String>() {{
            add("A");
            add("B");
            add("C");
        }};
        System.out.println(list4);

    }

    public void lickedListExample(){
        // 也是List的实现类，只不过它是采用的链式实现，是一个双向链表
        // LinkedList不仅可以当做List来使用，也可以当做双端队列使用

    }


    // 迭代器:for-each语句只是语法糖,内部本质上也是迭代器在处理
    // 得益于Iterable提供的迭代器生成方法，实际上只要是实现了迭代器接口的类（我们自己写的都行），都可以使用foreach语法
    // 列表的实现不同，遍历方式也不同，但是都是按照迭代器的标准进行了实现，而不需要关心集合类是如何实现
    public void iteratorExample(){

        List<String> list = Arrays.asList("A", "B", "C");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {    //每次循环一定要判断是否还有元素剩余
            System.out.println(iterator.next());  //如果有就可以继续获取到下一个元素
        }

        // 迭代器的使用是一次性的，用了之后就不能用了，如果需要再次进行遍历操作，那么需要重新生成一个迭代器对象。
        // 为了简便，我们可以直接使用foreach语法来快速遍历集合类，效果是完全一样的
        for (String s : list) {
            System.out.println(s);
        }

        list.forEach(System.out::println);  // Java8提供了一个支持Lambda表达式的forEach方法，这个方法接受一个Consumer，也就是对遍历的每一个元素进行的操作

        // ListIterator迭代器是针对于List的强化版本，增加了更多方便的操作
        // 因为List是有序集合，所以它支持两种方向的遍历操作，不仅能从前向后，也可以从后向前
        // 这种迭代器因为能够双向遍历，所以说可以反复使用
        ListIterator<String> listIterator = list.listIterator();
        listIterator.next();   //此时得到A
        listIterator.set("X");  //将A原本位置的上的元素设定为成新的
        System.out.println(list);

    }



    // Queue和Deque
    public void queueExample(){
        // 根据LinkedList的继承关系,可以直接将一个LinkedList当做一个队列来使用
        Queue<String> queue = new LinkedList<>();   // 当做队列使用，还是很方便的
        queue.offer("AA");
        queue.offer("BB");
        System.out.println(queue.poll());
        System.out.println(queue.poll());

        // 双端队列Deque既可以当做普通队列使用，也可以当做栈来使用
        Deque<String> deque = new LinkedList<>();
        deque.push("AAA");
        deque.push("BBB");
        System.out.println(deque.pop());
        System.out.println(deque.pop()); // 得到的顺序和插入顺序是完全相反的

        // 测试一下反向迭代器和正向迭代器
        Deque<String> deque3 = new LinkedList<>();

        deque3.addLast("AAAA");
        deque3.addLast("BBBB");

        Iterator<String> descendingIterator = deque3.descendingIterator();
        System.out.println(descendingIterator.next());

        Iterator<String> iterator3 = deque3.iterator();
        System.out.println(iterator3.next());


        // 还有其他的实现类可以实现队列接口
        Deque<String> deque9 = new ArrayDeque<>();   //数组实现的栈和队列

        Queue<Integer> queue9= new PriorityQueue<>();
        System.out.println("优先级队列可以根据每一个元素的优先级，对出队顺序进行调整，默认情况按照自然顺序");
        queue9.offer(10);
        queue9.offer(4);
        queue9.offer(5);
        System.out.println(queue9.poll());
        System.out.println(queue9.poll());
        System.out.println(queue9.poll());


        System.out.println("优先级队列的自定义比较规则实现,需要给一个Comparator的实现");
        Queue<Integer> queue8 = new PriorityQueue<>((a, b) -> b - a);   //按照从大到小顺序出队
        queue8.offer(10);
        queue8.offer(4);
        queue8.offer(5);
        System.out.println(queue8.poll());
        System.out.println(queue8.poll());
        System.out.println(queue8.poll());

        System.out.println("优先级队列只能保证出队顺序是按照优先级进行,队列中所有的元素不都是按照优先级排放的");





    }

    public static void main(String[] args) {
        BasicCollectionDemo basicCollectionDemo =new BasicCollectionDemo();
        basicCollectionDemo.listExample();
        basicCollectionDemo.lickedListExample();
        basicCollectionDemo.iteratorExample();
        basicCollectionDemo.queueExample();

    }

}
